using NICWebApi.Extensions.Caching.Implementations;
using NICWebApi.Extensions.Caching.Interfaces;
using NICWebApi.Extensions.Caching.Options;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// 缓存服务集合扩展方法
/// </summary>
public static class CachingServiceCollectionExtensions
{
    /// <summary>
    /// 添加缓存服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddCaching(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        // 注册缓存键生成器
        services.TryAddSingleton<ISimpleCacheKeyGenerator, DefaultCacheKeyGenerator>();

        // 配置 CachingOptions
        var cachingOptions = Utils.GetOptions();
        services.Configure<CachingOptions>(options =>
        {
            options.KeyPrefix = cachingOptions.KeyPrefix;
            options.KeySeparator = cachingOptions.KeySeparator;
            options.DefaultExpirationSeconds = cachingOptions.DefaultExpirationSeconds;
            options.UseDistributedCache = cachingOptions.UseDistributedCache;
            options.UseMemoryCache = cachingOptions.UseMemoryCache;
            options.RedisConnectionString = cachingOptions.RedisConnectionString;
            options.UseSerializer = cachingOptions.UseSerializer;
            options.EnableStatistics = cachingOptions.EnableStatistics;
            options.SizeLimit = cachingOptions.SizeLimit;

            // 复制特定提供程序选项
            if (cachingOptions.ProviderSpecificOptions != null)
            {
                options.ProviderSpecificOptions = cachingOptions.ProviderSpecificOptions;
            }
        });

        // 添加内存缓存
        if (cachingOptions.UseMemoryCache)
        {
            AddMemoryCache(services, cachingOptions);
        }

        // 添加分布式缓存
        if (cachingOptions.UseDistributedCache)
        {
            AddDistributedCache(services, cachingOptions);
        }

        // 如果两者都未启用，则默认使用内存缓存
        if (!cachingOptions.UseMemoryCache && !cachingOptions.UseDistributedCache)
        {
            AddMemoryCache(services, cachingOptions);
        }

        services.AddCacheInterceptor();

        return services;
    }

    /// <summary>
    /// 添加缓存服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configure">配置选项</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddCaching(this IServiceCollection services, Action<CachingOptions> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        // 配置 CachingOptions
        var cachingOptions = new CachingOptions();
        configure(cachingOptions);
        services.Configure<CachingOptions>(options =>
        {
            options.KeyPrefix = cachingOptions.KeyPrefix;
            options.KeySeparator = cachingOptions.KeySeparator;
            options.DefaultExpirationSeconds = cachingOptions.DefaultExpirationSeconds;
            options.UseDistributedCache = cachingOptions.UseDistributedCache;
            options.UseMemoryCache = cachingOptions.UseMemoryCache;
            options.RedisConnectionString = cachingOptions.RedisConnectionString;
            options.UseSerializer = cachingOptions.UseSerializer;
            options.EnableStatistics = cachingOptions.EnableStatistics;
            options.SizeLimit = cachingOptions.SizeLimit;

            // 复制特定提供程序选项
            if (cachingOptions.ProviderSpecificOptions != null)
            {
                options.ProviderSpecificOptions = cachingOptions.ProviderSpecificOptions;
            }
        });

        // 注册缓存键生成器
        services.TryAddSingleton<ISimpleCacheKeyGenerator, DefaultCacheKeyGenerator>();

        // 添加内存缓存
        if (cachingOptions.UseMemoryCache)
        {
            AddMemoryCache(services, cachingOptions);
        }

        // 添加分布式缓存
        if (cachingOptions.UseDistributedCache)
        {
            AddDistributedCache(services, cachingOptions);
        }

        // 如果两者都未启用，则默认使用内存缓存
        if (!cachingOptions.UseMemoryCache && !cachingOptions.UseDistributedCache)
        {
            AddMemoryCache(services, cachingOptions);
        }

        services.AddCacheInterceptor();

        return services;
    }

    /// <summary>
    /// 添加内存缓存
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="options">缓存选项</param>
    private static void AddMemoryCache(IServiceCollection services, CachingOptions options)
    {
        // 添加内存缓存
        services.AddMemoryCache(memoryCacheOptions =>
        {
            if (options.SizeLimit.HasValue)
            {
                memoryCacheOptions.SizeLimit = options.SizeLimit.Value;
            }
        });

        // 注册内存缓存服务
        services.TryAddSingleton<ISimpleCacheService, MemoryCacheService>();
    }

    /// <summary>
    /// 添加分布式缓存
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="options">缓存选项</param>
    private static void AddDistributedCache(IServiceCollection services, CachingOptions options)
    {
        // 配置 Redis
        if (!string.IsNullOrEmpty(options.RedisConnectionString))
        {
            services.AddStackExchangeRedisCache(redisOptions =>
            {
                redisOptions.Configuration = options.RedisConnectionString;

                // 应用特定于 Redis 的选项
                if (options.ProviderSpecificOptions?.TryGetValue("Redis", out var redisConfig) == true &&
                    redisConfig is System.Collections.Generic.Dictionary<string, object> redisConfigDict)
                {
                    if (redisConfigDict.TryGetValue("InstanceName", out var instanceName) && instanceName is string name)
                    {
                        redisOptions.InstanceName = name;
                    }

                    if (redisConfigDict.TryGetValue("ConfigurationOptions", out var configOptions) && configOptions != null)
                    {
                        redisOptions.ConfigurationOptions = StackExchange.Redis.ConfigurationOptions.Parse(configOptions.ToString());
                    }
                }
            });
        }
        else
        {
            // 如果未配置 Redis 连接字符串，则使用内存分布式缓存
            services.AddDistributedMemoryCache();
        }

        // 注册分布式缓存服务实现
        services.TryAddSingleton<ISimpleCacheService, DistributedCacheService>();
    }
}